package com.wdy.golden.tinysql.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;

/**
 * @author Dongye_Wu
 * @version: 1.0.0
 * @Description: TODO
 * @date 2020年4月11日 下午3:54:49
 */
public class ArgumentUtil {
	public static final String ARGUMENT_SEPARATOR = ".";
	
	public static void processArgumentJson(JSONObject jsonObj, String paramName,  Map<String, Object> argMap){

		for (String key : jsonObj.keySet()) {
			Object obj = jsonObj.get(key);
			String currKey = paramName + ARGUMENT_SEPARATOR + key;
			
			if(obj instanceof JSONObject) {
				processArgumentJson( (JSONObject)obj, currKey, argMap);
			}else if(obj instanceof JSONArray) {
				JSONArray jArr = (JSONArray)obj;
				if(jArr!=null && jArr.size()>0) {
					List<Object> oList = new ArrayList<Object>();
					for(int i=0;i<jArr.size();i++){
						Object objInArr = jArr.get(i);
						if(objInArr instanceof JSONObject) {
							processArgumentJson( (JSONObject)objInArr, currKey, argMap);
						}else{
							oList.add(objInArr);
						}
					}
					if(oList!=null && oList.size()>0) {
						argMap.put(currKey, oList);
					}
				}
			}else {
				argMap.put(currKey, obj==null?null:obj.toString());
			}
		}
	}

	public static void processOneArgument(String paramName, Object arg, Map<String, Object> argMap) {		
		if(ClazzUtil.isCustomObject(arg) || ClazzUtil.isMap(arg)) {			
			JSONObject jsonObj = JSON.parseObject(
					JSON.toJSONString(arg, 
							SerializerFeature.NotWriteDefaultValue, SerializerFeature.WriteBigDecimalAsPlain,
							SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteEnumUsingName,
							SerializerFeature.WriteMapNullValue
							),
					Feature.OrderedField
					);
			processArgumentJson(jsonObj, paramName, argMap);
		}else {
			argMap.put(paramName, arg.toString());
		}
	}

	public static Map<String, Object> processArguments(Method method, Object[] args) {
		Map<String, Object> argMap = null;

		Parameter[] parameters = method.getParameters();

		if (parameters != null && parameters.length > 0) {
			argMap = new LinkedHashMap<String, Object>();
			for (int i = 0; i < parameters.length; i++) {
				processOneArgument(parameters[i].getName(), args[i], argMap);
			}
		}
		return argMap;
	}
	
	//----------------------------------------------------------------------

	public static List<Map<String, Object>> processListArguments(Method method, Object[] args, List<String> batchParamList) {
		List<Map<String, Object>> argMapList = null;

		Parameter[] parameters = method.getParameters();

		if (parameters != null && parameters.length > 0) {
			argMapList = new ArrayList<Map<String, Object>>();
			Map<String, Object> argMap = null;
			for (int i = 0; i < parameters.length; i++) {
				if(ClazzUtil.isList(parameters[i].getType())) {
					List<?> argList = (List<?>)args[i];
					for(Object argObj : argList) {
						Field[] fields = argObj.getClass().getDeclaredFields();
						if(fields.length>0) {
							argMap = new HashMap<String, Object>();
							for(Field field : fields) {
								if (Modifier.isFinal(field.getModifiers())) {
									continue;
								}
								String k = parameters[i].getName()+ARGUMENT_SEPARATOR+field.getName();
								if(batchParamList!=null && batchParamList.size()>0) {
									if(!batchParamList.contains(k)) {
										continue;
									}
								}	
								try {
									argMap.put(
											k, 
											ReflectionUtil.invokeMethod(argObj.getClass().getDeclaredMethod(StringUtil.underlineToGetMethodName(field.getName())), argObj)
											);
								} catch (NoSuchMethodException | SecurityException e) {
									e.printStackTrace();
								}
							}
						}
						argMapList.add(argMap);
					}
				}
			}
		}
		
		return argMapList;
	}
	
}
